#include <iostream>
#include <string>

using namespace std;

class HasPtr
{
public:
    HasPtr(const string &s = string()) : ps(new string(s)), i(0), use(new size_t(1)) {}
    HasPtr(const HasPtr &hp) : ps(hp.ps), i(hp.i), use(hp.use) { ++*use; }

    HasPtr &operator=(const HasPtr &);
    HasPtr &operator=(const string &);
    string &operator*() const;
    ~HasPtr();

private:
    string *ps;
    int i;
    size_t *use;
};

HasPtr::~HasPtr()
{
    cout << "~HasPtr(): " << endl;
    if (--(*use) == 0) // last one?
    {
        cout << "last one so delete:" << *ps << endl;
        delete ps;
        ps = nullptr;
        delete use;
        use = nullptr;
    }
    else
    {
        cout << "not last one:" << *ps << endl;
    }
}

inline HasPtr &HasPtr::operator=(const HasPtr &rhs)
{
    ++(*rhs.use);
    if (--(*use) == 0) // last one?
    {
        delete ps;
        ps = nullptr;
        delete use;
        use = nullptr;
    }
    ps = rhs.ps;
    i = rhs.i;
    use = rhs.use;
    return *this;
}

inline HasPtr &HasPtr::operator=(const string &rhs)
{
    *ps = rhs;
    return *this;
}

string &HasPtr::operator*() const
{
    return *ps;
}

int main()
{
    HasPtr hp("hi mom!");
    HasPtr hp2(hp);
    hp2 = "hi dad!";
    cout << "hp:\t" << *hp << endl;
    cout << "hp2:\t" << *hp2 << endl;
}
